package com.gaojinqi.sys.core.shiro.config;

import com.gaojinqi.base.core.util.SpringContextHolder;
import com.gaojinqi.sys.config.properties.ShiroAuthProperties;
import com.gaojinqi.sys.core.shiro.filter.JwtFilter;
import com.gaojinqi.sys.core.shiro.rest.RestPathMatchingFilterChainResolver;
import com.gaojinqi.sys.core.shiro.rule.RolePermRule;
import com.gaojinqi.sys.core.shiro.rule.ShiroFilterRulesProvider;
import com.gaojinqi.sys.core.shiro.util.JwtTokenHelper;
import com.gaojinqi.sys.core.shiro.util.UserCacheHelper;
import lombok.extern.slf4j.Slf4j;
import org.apache.shiro.spring.web.ShiroFilterFactoryBean;
import org.apache.shiro.web.filter.mgt.DefaultFilterChainManager;
import org.apache.shiro.web.servlet.AbstractShiroFilter;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.scheduling.annotation.Async;

import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;

/**
 * shiro 过滤器配置
 *
 * @author gaojinqi
 * @version 1.0
 * @since 2020年05月12日
 */
@Slf4j
@Configuration
public class ShiroFilterConfiguration {

    @Autowired
    private ShiroAuthProperties shiroAuthProperties;
    @Autowired(required = false)
    private ShiroFilterRulesProvider filterRulesProvider;

    @Bean
    public JwtFilter jwtFilter(UserCacheHelper userCacheHelper, JwtTokenHelper jwtTokenHelper) {
        JwtFilter jwtFilter = new JwtFilter();
        jwtFilter.setUserCacheHelper(userCacheHelper);
        jwtFilter.setJwtTokenHelper(jwtTokenHelper);
        return jwtFilter;
    }

    /**
     * 获取过滤链的规则
     */
    public Map<String, String> getFilterChainDefinitionMap() {
        LinkedHashMap<String, String> filterChainDefinitionMap = new LinkedHashMap<>();
        // 设置免认证 url
        List<String> anonUrls = shiroAuthProperties.getAnonUrl();
        for (String url : anonUrls) {
            filterChainDefinitionMap.put(url, "anon");
        }
        // 配置退出过滤器，其中具体的退出代码 Shiro已经替我们实现了
        //filterChainDefinitionMap.put(shiroAuthProperties.getLogoutUrl(), "logout");
        // 除上以外所有 url都必须认证通过才可以访问，未通过认证自动访问 LoginUrl
        //filterChainDefinitionMap.put("/**", "user");
        // 动态URL
        if (filterRulesProvider != null) {
            List<RolePermRule> rolePermRules = filterRulesProvider.findRolePermRules();
            if (rolePermRules != null) {
                rolePermRules.forEach(rule -> {
                    StringBuilder chain = rule.toFilterChain();
                    if (null != chain) {
                        filterChainDefinitionMap.putIfAbsent(rule.getUrl(), chain.toString());
                    }
                });
            }
        }
        return filterChainDefinitionMap;
    }

    /**
     * 刷新动态过滤器规则
     */
    @Async
    public synchronized void reloadFilterChain() {
        ShiroFilterFactoryBean shiroFilterFactoryBean = SpringContextHolder.getBean(ShiroFilterFactoryBean.class);
        AbstractShiroFilter abstractShiroFilter = null;
        try {
            abstractShiroFilter = (AbstractShiroFilter) shiroFilterFactoryBean.getObject();
            if (abstractShiroFilter != null) {
                RestPathMatchingFilterChainResolver filterChainResolver = (RestPathMatchingFilterChainResolver) abstractShiroFilter.getFilterChainResolver();
                DefaultFilterChainManager filterChainManager = (DefaultFilterChainManager) filterChainResolver.getFilterChainManager();
                filterChainManager.getFilterChains().clear();
                shiroFilterFactoryBean.getFilterChainDefinitionMap().clear();
                shiroFilterFactoryBean.setFilterChainDefinitionMap(this.getFilterChainDefinitionMap());
                shiroFilterFactoryBean.getFilterChainDefinitionMap().forEach(filterChainManager::createChain);
            }
        } catch (Exception e) {
            log.error(String.format("刷新动态过滤器规则失败 msg = %s", e.getMessage()), e);
        }
    }

}
